#include <isa.h>
#include <cpu.h>
#include <memory/paddr.h>
#include <verilated.h>
#include <verilated_vcd_c.h>
#include "VRISCV_BOARD.h"

static char* bin_file = NULL;//img文件
static char* elf_file = NULL;//elf文件
static char* log_file = NULL;//log文件
static char* diff_file = NULL;//diff动态链接库
static int diff_port = 3085;//ref_difftest_raise_intr中的port


VerilatedContext* env = NULL;
VRISCV_BOARD* cpu = NULL;
IFDEF(CONFIG_TRACE,VerilatedVcdC* tfp = NULL);
unsigned char isa_logo[] = {
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x5f, 0x20,
  0x20, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x5f, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x28, 0x5f, 0x29, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x7c, 0x20, 0x20, 0x5c, 0x2f, 0x20, 0x20, 0x7c, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20,
  0x7c, 0x0a, 0x20, 0x20, 0x5f, 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x20, 0x5f,
  0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x5f, 0x5f, 0x20, 0x5f, 0x5f, 0x5f, 0x5f,
  0x5f, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x5f, 0x20, 0x7c, 0x20,
  0x5c, 0x20, 0x20, 0x2f, 0x20, 0x7c, 0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x20,
  0x5f, 0x20, 0x5f, 0x5f, 0x20, 0x20, 0x5f, 0x20, 0x20, 0x20, 0x5f, 0x20,
  0x20, 0x5f, 0x5f, 0x20, 0x5f, 0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20,
  0x27, 0x5f, 0x5f, 0x7c, 0x20, 0x2f, 0x20, 0x5f, 0x5f, 0x7c, 0x2f, 0x20,
  0x5f, 0x5f, 0x7c, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5c, 0x20, 0x5c,
  0x20, 0x2f, 0x20, 0x2f, 0x20, 0x7c, 0x20, 0x7c, 0x5c, 0x2f, 0x7c, 0x20,
  0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20, 0x7c, 0x20, 0x27, 0x5f, 0x20, 0x5c,
  0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x2f, 0x20, 0x5f, 0x60, 0x20,
  0x7c, 0x20, 0x7c, 0x0a, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x7c, 0x20,
  0x5c, 0x5f, 0x5f, 0x20, 0x5c, 0x20, 0x28, 0x5f, 0x5f, 0x20, 0x20, 0x20,
  0x20, 0x20, 0x20, 0x20, 0x20, 0x5c, 0x20, 0x56, 0x20, 0x2f, 0x20, 0x20,
  0x7c, 0x20, 0x7c, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x28, 0x5f, 0x7c,
  0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x5f, 0x7c,
  0x20, 0x7c, 0x20, 0x28, 0x5f, 0x7c, 0x20, 0x7c, 0x20, 0x7c, 0x0a, 0x20,
  0x7c, 0x5f, 0x7c, 0x20, 0x20, 0x7c, 0x5f, 0x7c, 0x5f, 0x5f, 0x5f, 0x2f,
  0x5c, 0x5f, 0x5f, 0x5f, 0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  0x20, 0x5c, 0x5f, 0x2f, 0x20, 0x20, 0x20, 0x7c, 0x5f, 0x7c, 0x20, 0x20,
  0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x20,
  0x7c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f, 0x2c, 0x5f, 0x7c, 0x5c, 0x5f, 0x5f,
  0x2c, 0x5f, 0x7c, 0x5f, 0x7c, 0x0a, '\0'  /* Termination Character is indispensable! */
};


extern mode launch_mode;
void welcome(){
	printf("\nwelcome to %s-NPC",ANSI_FMT(CONFIG_ISA,ANSI_FG_YELLOW ANSI_BG_RED));
	if(launch_mode == STD){
		printf("\n\n");
	}else{
		printf(ANSI_FMT(" (sdb)",ANSI_FG_GREEN) "\n");
		printf(ANSI_FMT("%s\n\n",ANSI_FG_BLUE),isa_logo);
	}
}

long bin_init(){
	Log("binary file initializing %s", ANSI_FMT("START", ANSI_FG_GREEN));

	Assert(bin_file,"<FILE>: BIN DO NOT EXIST");
	printf("%s:%s\n",ANSI_FMT("READING",ANSI_FG_GREEN),bin_file);
	FILE* fp = fopen(bin_file,"rb");
	Assert(fp,"<FILE>: CANNOT READ FROM BIN\n");
	fseek(fp,0,SEEK_END);
	long fsize = ftell(fp);

	rewind(fp);
	assert(fread(paddr_to_ptr(PMEM_RESET),fsize,1,fp) == 1);
	fclose(fp);
	
	Log("binary file initializing %s\n", ANSI_FMT("FINISH", ANSI_FG_GREEN));

	return fsize;
}
extern vluint64_t sim_time; 
void clk_update(){//1clk
	cpu->eval();
	IFDEF(CONFIG_TRACE,tfp->dump(sim_time));
	sim_time++;
	cpu->clk^=1;

	cpu->eval();	
	IFDEF(CONFIG_TRACE,tfp->dump(sim_time));
	sim_time++;
	cpu->clk^=1;
}

void half_clk_update(){
	cpu->eval();
	IFDEF(CONFIG_TRACE,tfp->dump(sim_time));
	sim_time++;
	cpu->clk^=1;
} 

//下降沿读取
//上升沿执行和写入
void cpu_init(){
	env = new VerilatedContext;
	cpu = new VRISCV_BOARD(env);
#ifdef CONFIG_TRACE
	Verilated::traceEverOn(true);
	tfp = new VerilatedVcdC();
	cpu->trace(tfp,0);
	tfp->open("wave.vcd");
#endif

	Log("CPU initializing %s", ANSI_FMT("START", ANSI_FG_GREEN));

	cpu->clk = 0;
	cpu->reset = 1;

	clk_update();
	cpu->reset = 0;
	
	for(int i = 0;i<7;i++) clk_update();

	Log("CPU initializing %s\n", ANSI_FMT("FINISH", ANSI_FG_GREEN));
}

void log_init(const char* log_file);
extern "C" void disasm_init(const char *triple); 
void buffer_init();
void mem_buffer_init();
void elf_init(const char* fileName);
void difftest_init(const char* ref_so_file, long img_size, int port);
void device_init();

void std_monitor_init(int argc,char** argv){
	bin_file = argv[1];
	log_file = argv[2];
	elf_file = argv[3];
	diff_file = argv[4];

	//CPU BASIS
#ifdef CONFIG_ITRACE	
	log_init(log_file);
#endif
	mem_init();

	long img_size = bin_init();
	cpu_init();
	
	//ITRACE INIT	
#ifdef CONFIG_ITRACE
	disasm_init("riscv32-pc-linux-gnu");
	buffer_init();
#endif

	//FTRACE INIT
#ifdef CONFIG_FTRACE
	elf_init(elf_file);
#endif

	//MTRACE INIT
#ifdef CONFIG_MTRACE
	mem_buffer_init();
#endif	

	
	//DIFFTEST INIT
#ifdef CONFIG_DIFFTEST
	difftest_init(diff_file, img_size, diff_port);
#endif

	//DEVICE INIT
	device_init();

	welcome();
}


